package com.alibaba.cirtus.ots.application.adapter.ability.facade.serviceV2.crm;

import com.alibaba.acm.shaded.com.google.common.collect.Lists;
import com.alibaba.cirtus.ots.application.adapter.ability.model.enums.MnSAPStatus;
import com.alibaba.citrus.ots.common.annotation.EpochTransactional;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.CalculatePercentage;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.citrus.ots.common.util.SpringContextUtil;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByCodes2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByCodes2Response;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationById2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganizationByTypeRequest;
import com.epoch.app.bcorder.model.dto.BatchQueryCompanyRequest;
import com.epoch.app.bcorder.model.dto.MonthContractAndRollingCountResponse;
import com.epoch.app.bcorder.model.dto.MonthlyPlanOfCcommerceLoadListRequest;
import com.epoch.app.bcorder.model.dto.OrganizationSDO;
import com.epoch.app.bcorder.model.dto.PlanScItemExtendLoadListRequest;
import com.epoch.app.bcorder.model.dto.QueryQuantityListByAddressAndScItemRequest;
import com.epoch.app.bcorder.model.dto.QueryQuantityListByAddressAndScItemResponse;
import com.epoch.app.bcorder.model.dto.ScItemSDO;
import com.epoch.app.bcorder.model.dto.SearchScItemRequest;
import com.epoch.app.bcorder.sales_plan.monthlyplanofccommerce.model.MonthlyPlanOfCcommerce;
import com.epoch.app.bcorder.sales_plan.monthlyplanofccommerce.service.MonthlyPlanOfCcommerceService;
import com.epoch.app.bcorder.sales_plan.planscitem.dto.BatchQueryByBizIdRequest;
import com.epoch.app.bcorder.sales_plan.planscitem.model.PlanScItem;
import com.epoch.app.bcorder.sales_plan.planscitem.service.PlanScItemService;
import com.epoch.app.bcorder.sales_plan.planscitemextend.dto.CreatePlanScItemExtendResponse;
import com.epoch.app.bcorder.sales_plan.planscitemextend.dto.UpdatePlanScItemExtendResponse;
import com.epoch.app.bcorder.sales_plan.planscitemextend.model.PlanScItemExtend;
import com.epoch.app.bcorder.sales_plan.planscitemextend.service.PlanScItemExtendService;
import com.epoch.app.bcorder.sales_plan.salesplan.dto.LoadSalesPlanListRequest;
import com.epoch.app.bcorder.sales_plan.salesplan.dto.UpdateSalesPlanResponse;
import com.epoch.app.bcorder.sales_plan.salesplan.model.SalesPlan;
import com.epoch.app.bcorder.sales_plan.salesplan.service.SalesPlanService;
import com.epoch.app.bcorder.sales_plan.salesplanscitem.dto.SalesPlanScItemLoadListRequest;
import com.epoch.app.bcorder.sales_plan.salesplanscitem.model.SalesPlanScItem;
import com.epoch.app.bcorder.sales_plan.salesplanscitem.service.SalesPlanScItemService;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.BcOrderService;
import com.epoch.app.otsapplicationadaptersdk.crm.MnCrmCommResponse;
import com.epoch.app.otsapplicationadaptersdk.crm.MnCrmCommSDO;
import com.epoch.app.otsapplicationadaptersdk.crm.MnCrmIf003Request;
import com.epoch.app.otsapplicationadaptersdk.crm.MnCrmIf003SDO;
import com.epoch.app.otsapplicationadaptersdk.crmv2.mncrmif003v2.service.MnCrmIf003V2Service;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhoubc
 * @description: CRM请求平台月度计划调整回复
 * @date 2021/9/25 1:07
 */
@Component
public class MnCrmIf003V2ServiceImpl implements MnCrmIf003V2Service {
    private static final Log log = Log.getLogger(com.alibaba.cirtus.ots.application.adapter.ability.facade.service.crm.MnCrmIf003ServiceImpl.class);

    @Resource
    private PlanScItemService planScItemService;

    @Resource
    private SalesPlanService salesPlanService;

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private PlanScItemExtendService planScItemExtendService;

    @Resource
    private BcOrderService bcOtsService;

    @Resource
    private SalesPlanScItemService salesPlanScItemService;

    @Resource
    private com.epoch.app.bcorder.service.SalesPlanService planService;

    @Resource
    private MonthlyPlanOfCcommerceService monthlyPlanOfCcommerceService;

    @ProcessInvoker(remark = "MnCrmIf003Service", errorCode = "OTS-02-007-00-16-999", printLog = true)
    @Override
    public MnCrmCommResponse externalReplySalePlanAdjust(MnCrmIf003Request mnCrmIf003Request) {
        // 1、设置消息头
        MnCrmCommResponse commResponse = MnCrmCommResponse.builder().build();
        commResponse.setMessageId(mnCrmIf003Request.getMessageHeader().getMessageId());
        commResponse.setInterfacePath(mnCrmIf003Request.getMessageHeader().getInterfacePath());
        List<MnCrmIf003SDO> data = mnCrmIf003Request.getData();
        if (CollectionUtils.isEmpty(data)) {
            MnCrmCommSDO commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.ERROR.getCode()).resultMessage("入参数组不可为空").build();
            commResponse.setData(commSDO);
            log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail {}", JSONObject.toJSONString(commSDO));
            return commResponse;
        }
        List<String> superiorSalesOrgCodeList = Lists.newArrayList("6000","6004");
        // 筛选电商月度计划和分子公司月度计划
        List<MnCrmIf003SDO> salesPlanReplays = data.stream().filter(it -> superiorSalesOrgCodeList.contains(it.getSalesOrganizationCode())).collect(Collectors.toList());
        List<MnCrmIf003SDO> eCommerceSalesPlanReplay = data.stream().filter(it -> "1171".equals(it.getSalesOrganizationCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(salesPlanReplays) && CollectionUtils.isEmpty(eCommerceSalesPlanReplay)) {
            log.error("没有调整回复货品,请查看请求入参");
            MnCrmCommSDO commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.ERROR.getCode()).resultMessage("没有回复货品").build();
            commResponse.setData(commSDO);
            return commResponse;
        }
        // 电商月度计划同步
        String commerceErrMsg = null;
        if (CollectionUtils.isNotEmpty(eCommerceSalesPlanReplay)) {
            commerceErrMsg = processCommerceSalesPlan(eCommerceSalesPlanReplay);
            if (CollectionUtils.isEmpty(salesPlanReplays)) {
                MnCrmCommSDO commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.SUCCESS.getCode()).resultMessage("电商月度计划回复成功").build();
                if(StringUtils.isNotBlank(commerceErrMsg)){
                    commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.ERROR.getCode()).resultMessage(commerceErrMsg).build();
                }
                commResponse.setData(commSDO);
                return commResponse;
            }
        }

        List<String> notExistOrg = Lists.newArrayList();
        List<String> notExistItems = Lists.newArrayList();
        List<String> notExistPlan = Lists.newArrayList();
        List<String> notExistPlanScItems = Lists.newArrayList();
        Map<String, Object> resultMap = Maps.newHashMap();
        // 分子公司月度计划处理
        if (CollectionUtils.isNotEmpty(salesPlanReplays)) {
            try {
                // 扫描是否有不合规的数据
                Set<String> customerCodesSet = salesPlanReplays.stream().map(MnCrmIf003SDO::getCustomerCode).collect(Collectors.toSet());
                Map</* CustomerCode 业务组织单元对应客户编码 */String, /* 回复货品列表 */List<MnCrmIf003SDO>> orgUnitRespScItemMap = Maps.newHashMap();
                Map</* CustomerCode 业务组织单元对应客户编码 */String, /* 计划货品列表 */List<PlanScItem>> orgUnitPlanScItemMap = Maps.newHashMap();
                Map</* CustomerCode 业务组织单元对应客户编码 */String, /* 调整计划 */SalesPlan> orgUnitSalePlanMap = Maps.newHashMap();
                Map</* CustomerCode 业务组织单元对应客户编码 */String, /* 业务单元编码 */String> orgUnitCodeMap = Maps.newHashMap();
                Map</* CustomerCode 业务组织单元对应客户编码 */String, /* 货品Map */Map<String, ScItemSDO>> orgUnitScItemMap = Maps.newHashMap();
                // 可能会有多个业务单元合并回复
                for (String customerCode : customerCodesSet) {
                    //客户x货品
                    List<MnCrmIf003SDO> customerAndScItemList = salesPlanReplays.stream().filter(it -> it.getCustomerCode().equals(customerCode)).collect(Collectors.toList());
                    //判断公司是否存在
                    MnCrmIf003SDO crmIf003SDO = customerAndScItemList.get(0);
                    String orgBusinessUnitCode = getOrgBusinessUnitCode(crmIf003SDO);
                    if(StringUtils.isBlank(orgBusinessUnitCode)){
                        log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 组织不存在,customerCode：{}", crmIf003SDO.getCustomerCode());
                        notExistOrg.add(customerCode);
                        continue;
                    }
                    orgUnitCodeMap.put(crmIf003SDO.getCustomerCode(), orgBusinessUnitCode);

                    //获取回复货品的外部编码映射
                    List<String> itemCodes = getScItemCodesBy003SDOs(customerAndScItemList);
                    Map<String, ScItemSDO> itemByOuterIds = getScItemByOuterIds(itemCodes);
                    orgUnitScItemMap.put(customerCode, itemByOuterIds);

                    //查询调整提报货品
                    List<PlanScItem> reportItems = getPlanScItemListByTimeAndBusiness(orgBusinessUnitCode, crmIf003SDO, orgUnitSalePlanMap);
                    if (CollectionUtils.isEmpty(reportItems)) {
                        String errMsg = "orgBusinessUnitCode："+ orgBusinessUnitCode + "，planTime:" + crmIf003SDO.getPlanTime() + "，customerCode:" + crmIf003SDO.getCustomerCode();
                        log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 月度调整非待回复状态或月度调整没有提报货品 " +errMsg);
                        notExistPlan.add(errMsg);
                        continue;
                    }
                    orgUnitPlanScItemMap.put(customerCode, reportItems);
                    Map<String, PlanScItem> planScItemMap = reportItems.stream().collect(Collectors.toMap(PlanScItem::getScItemId, o -> o));

                    // 判断是否有不存在的货品
                    List<MnCrmIf003SDO> respScItemList = Lists.newArrayList(customerAndScItemList);
                    for (MnCrmIf003SDO if003SDO : customerAndScItemList) {
                        if (!itemByOuterIds.containsKey(if003SDO.getScItemCode())) {
                            log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 货品不存在或不可用，scItemCode={}", if003SDO.getScItemCode());
                            notExistItems.add(if003SDO.getScItemCode());
                            respScItemList.remove(if003SDO);
                            continue;
                        } else {
                            // 不存在的提报货品需要落库
                            ScItemSDO scItemSDO = itemByOuterIds.get(if003SDO.getScItemCode());
                            if (!planScItemMap.containsKey(scItemSDO.getScItemId())) {
                                String errMsg = "orgBusinessUnitCode："+ orgBusinessUnitCode + "，planTime:" + if003SDO.getPlanTime() + "，scItemCode:" + scItemSDO.getOuterId();
                                log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 货品不在提报货品中，详情={}", errMsg);
                                notExistPlanScItems.add(scItemSDO.getOuterId());
                                respScItemList.remove(if003SDO);
                                continue;
                            }

                        }
                    }
                    orgUnitRespScItemMap.put(customerCode, respScItemList);
                }

                // 4、存在不合规数据，就返回错误
                if (CollectionUtils.isNotEmpty(notExistOrg)) {
                    resultMap.put("组织不存在，客户编码", notExistOrg);
                }
                if (CollectionUtils.isNotEmpty(notExistItems)) {
                    resultMap.put("货品不可用或不存在，货品编码", notExistItems);
                }
                if (CollectionUtils.isNotEmpty(notExistPlan)) {
                    resultMap.put("月度调整非待回复状态或月度调整没有提报货品，详情", notExistPlan);
                }
                if (CollectionUtils.isNotEmpty(notExistPlanScItems)) {
                    resultMap.put("回复货品对应月度调整提报货品不存在，详情", notExistPlanScItems);
                }

                List<String> notExistPlanByAdjust = Lists.newArrayList();
                Map</* planId */Long, Map<String, PlanScItemExtend>> existPlanScItemExtendMap = Maps.newHashMap();
                Map</* planId */Long, List<PlanScItemExtend>> planScItemExtendMap = Maps.newHashMap();
                // 5、逐个公司进行回复
                for (String customerCode : customerCodesSet) {
                    // 5.1 crm回复的货品
                    List<MnCrmIf003SDO> if003SDOS = orgUnitRespScItemMap.get(customerCode);
                    if(CollectionUtils.isEmpty(if003SDOS)){
                        log.info("MnCrmIf002ServiceImpl#externalReplySalePlanAdjust_crm_customer_resp_scItem_is_null,customer_code={}",customerCode);
                        continue;
                    }
                    // 5.2 获取订单平台提报的货品
                    List<PlanScItem> reportItems = orgUnitPlanScItemMap.get(customerCode);
                    if(CollectionUtils.isEmpty(reportItems)){
                        log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_ots_customer_report_scItem_is_null,customer_code={}",customerCode);
                        continue;
                    }
                    Map<String, PlanScItem> planScItemMap = reportItems.stream().collect(Collectors.toMap(PlanScItem::getScItemId, o -> o));
                    for (MnCrmIf003SDO mnCrmIf003SDO : if003SDOS) {
                        // 5.3 给回复量赋值
                        PlanScItem planScItem = buildPlanScItem(planScItemMap, orgUnitSalePlanMap, orgUnitCodeMap, orgUnitScItemMap.get(customerCode), mnCrmIf003SDO);
                        planScItemMap.put(planScItem.getScItemId(), planScItem);
                    }

                    // 3、更新业务单元维度的回复量
                    SalesPlan salesPlan = orgUnitSalePlanMap.get(customerCode);
                    List<PlanScItem> planScItems = Lists.newArrayList(planScItemMap.values());
                    List<PlanScItemExtend> extendList = planScItems.stream().map(it -> {
                        PlanScItemExtend planScItemExtend = new PlanScItemExtend();
                        BeanUtils.copyProperties(it, planScItemExtend);
                        planScItemExtend.setModel(2);
                        planScItemExtend.setModelId(String.valueOf(salesPlan.getId()));
                        return planScItemExtend;
                    }).collect(Collectors.toList());
                    // 没有符合条件数据直接截断
                    if (CollectionUtils.isEmpty(extendList)) {
                        log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 未查询到调整中的月度计划，客户编码={}", customerCode);
                        notExistPlanByAdjust.add(customerCode);
                        continue;
    //                    MnCrmCommSDO commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.ERROR.getCode()).resultMessage("订单平台未查询到调整中的月度计划").build();
    //                    commResponse.setData(commSDO);
    //                    return commResponse;
                    }
                    // 获取已经存在的计划货品扩展信息
                    existPlanScItemExtendMap.put(salesPlan.getId(), fetchExistPlanScItemExtend(salesPlan));
                    planScItemExtendMap.put(salesPlan.getId(), extendList);
                }
                if (CollectionUtils.isNotEmpty(notExistPlanByAdjust)) {
                    resultMap.put("调整中的月度计划不存在，客户编码", notExistPlanScItems);
                }
                // 统一事务处理
                SpringContextUtil.getBean(com.alibaba.cirtus.ots.application.adapter.ability.facade.serviceV2.crm.MnCrmIf003V2ServiceImpl.class).batchSaveOrUpdateCompanyScItemExtend(planScItemExtendMap, existPlanScItemExtendMap);
            } catch (Throwable e) {
                log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_occor_error ", e);
                throw e;
            }
        }

        MnCrmCommSDO commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.SUCCESS.getCode()).resultMessage("月度调整回复成功").build();
        if(CollectionUtils.isNotEmpty(eCommerceSalesPlanReplay) && commerceErrMsg!=null){
            resultMap.put("电商月度调整回复出错",commerceErrMsg);
        }
        if(resultMap.size() > 0){
            String resultMessage = JSON.toJSONString(resultMap);
            commSDO = MnCrmCommSDO.builder().resultType(MnSAPStatus.ERROR.getCode()).resultMessage(resultMessage).build();
        }
        commResponse.setData(commSDO);
        return commResponse;
    }

    @EpochTransactional(appCode = "bc_ots", dataSourceCode = "cr_ots", dataSourceType = "app")
    public void batchSaveOrUpdateCompanyScItemExtend(Map<Long, List<PlanScItemExtend>> planScItemExtendMap,Map<Long, Map<String, PlanScItemExtend>> existPlanScItemExtendMap) {
        if (MapUtils.isEmpty(planScItemExtendMap)) {
            return;
        }

        for (Long planId : planScItemExtendMap.keySet()) {
            // 更新月度计划状态
            SalesPlan updateRequest = new SalesPlan();
            updateRequest.setId(planId);
            updateRequest.setStatus(7);
            updateRequest.setCheckStatus(0);
            UpdateSalesPlanResponse updateSalesPlan = salesPlanService.updateSalesPlan(updateRequest);
            if (null == updateSalesPlan || updateSalesPlan.getCount() < 1) {
                log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail_update_plan_fail，{}", JSONObject.toJSONString(updateSalesPlan));
                throw new FacadeException("更新计划状态失败");
            }
            // 批量插入extend表
            boolean success = saveOrUpdateScItemExtend(planScItemExtendMap.get(planId), existPlanScItemExtendMap.get(planId));
        }
    }

    private Map<String, PlanScItemExtend> fetchExistPlanScItemExtend(SalesPlan salesPlan) {
        PlanScItemExtendLoadListRequest build = PlanScItemExtendLoadListRequest.newPlanScItemExtendLoadListRequestBuilder().build();
        build.setPlanId(String.valueOf(salesPlan.getParentId()));
        build.setModelId(String.valueOf(salesPlan.getId()));
        build.setBizId(salesPlan.getOrgBusinessUnitCode());
        build.setBizType(5);
        build.setPoolType(2);
        build.setStart(0);
        build.setLimit(1000);
        Result<List<PlanScItemExtend>> listResult = planScItemExtendService.loadPlanScItemExtendList(build);
        if (null == listResult || CollectionUtils.isEmpty(listResult.getResult())) {
            return Maps.newHashMap();
        }
        return listResult.getResult().stream().collect(Collectors.toMap(PlanScItemExtend::getScItemId, Function.identity()));
    }

    private String processCommerceSalesPlan(List<MnCrmIf003SDO> eCommerceSalesPlanReplay) {
        // 根据编码查组织
        BaselineGetOrganizationByCodes2Response organizationResult = baseDataService.baselineGetOrganizationByCodes2(BaselineGetOrganizationByCodes2Request.builder().ids(Lists.newArrayList("1171")).build());
        if (null == organizationResult || CollectionUtils.isEmpty(organizationResult.getResult())) {
            return "电商销售组织:" + 1171 + "没有在业务组织上维护或已禁用";
        }
        OrganizationSDO salesOrganization = organizationResult.getResult().get(0);
        // 根据组织里的parentId查业务单元
        Result<OrganizationSDO> organization = baseDataService.baselineGetOrganizationById2(BaselineGetOrganizationById2Request.builder().id(salesOrganization.getParentId()).build());
        if (null == organization || null == organization.getResult()) {
            return "电商销售组织:" + 1171 + "没有维护业务单元";
        }
        OrganizationSDO orgBusiness = organization.getResult();
        int sucNum = 0;
        for (MnCrmIf003SDO mnCrmIf003SDO : eCommerceSalesPlanReplay) {
            try {
                mnCrmIf003SDO.setSalesOrganizationCode(salesOrganization.getId());
                if (StringUtils.isBlank(mnCrmIf003SDO.getScItemCode()) && StringUtils.isBlank(mnCrmIf003SDO.getScItemGroup())) {
                    log.error("货品编码和货品组信息为空");
                    continue;
                }
                // 计划年月转换为时间戳
                long time = new SimpleDateFormat("yyyyMM").parse(mnCrmIf003SDO.getPlanTime().replace("-", "")).getTime();
                mnCrmIf003SDO.setPlanTime(String.valueOf(time));
                MonthlyPlanOfCcommerceLoadListRequest request = new MonthlyPlanOfCcommerceLoadListRequest();
                request.setPlanTime(mnCrmIf003SDO.getPlanTime());
                request.setOrgSaleOrganizationCode(mnCrmIf003SDO.getSalesOrganizationCode());
                request.setScItemGroupCode(mnCrmIf003SDO.getScItemGroup());
                request.setOuterId(mnCrmIf003SDO.getScItemCode());
                request.setCustomerCode(mnCrmIf003SDO.getCustomerCode());
                // TODO 可以优化成批量插入和更新, 数据量相对较少，优先级较低
                Result<List<MonthlyPlanOfCcommerce>> listResult = monthlyPlanOfCcommerceService.loadList(request);
                log.info("查询电商月度计划返回结果:{}", JSONObject.toJSONString(listResult));
                if (null != listResult && CollectionUtils.isNotEmpty(listResult.getResult())) {
                    // 更新
                    MonthlyPlanOfCcommerce monthlyPlanOfCcommerce = convertMonthlyPlanOfCommerce(mnCrmIf003SDO, orgBusiness, listResult);
                    monthlyPlanOfCcommerce.setId(listResult.getResult().get(0).getId());
                    monthlyPlanOfCcommerceService.update(monthlyPlanOfCcommerce);
                }
                if (null != listResult && CollectionUtils.isEmpty(listResult.getResult())) {
                    // 新增
                    MonthlyPlanOfCcommerce monthlyPlanOfCcommerce = convertMonthlyPlanOfCommerce(mnCrmIf003SDO, orgBusiness, listResult);
                    monthlyPlanOfCcommerce.setGmtCreate(new Date());
                    monthlyPlanOfCcommerceService.create(monthlyPlanOfCcommerce);
                }
                sucNum++;
            } catch (Throwable e) {
                log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_occor_error={},monthlyPlanOfCcommerce_sdo={}",e,JSONObject.toJSONString(mnCrmIf003SDO));
            }
        }

        if (sucNum == eCommerceSalesPlanReplay.size()) {
            return null;
        } else {
            StringBuilder msgBuilder = new StringBuilder();
            msgBuilder.append("电商月度调整回复部分成功，请注意排查，详情：").append("成功条数=").append(sucNum).append("总条数=").append(eCommerceSalesPlanReplay.size());
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail " + msgBuilder.toString());
            return msgBuilder.toString();
        }
    }

    private List<PlanScItem> getPlanScItemListByTimeAndBusiness(String orgBusinessUnitCode,
                                                                MnCrmIf003SDO crmIf003SDO,
                                                                Map<String, SalesPlan> orgUnitSalePlanMap) {
        // 2.1 查询调整待回复的月度计划
        long time = getPlanTime(crmIf003SDO);
        LoadSalesPlanListRequest planListRequest = LoadSalesPlanListRequest.builder()
                .planTime(String.valueOf(time))
                .orgBusinessUnitCode(orgBusinessUnitCode)
                .statusList(Lists.newArrayList(6, 7))
                .model(2)
                .build();
        Result<List<SalesPlan>> salesPlanList = getSalesPlanList(planListRequest);
        if (CollectionUtils.isEmpty(salesPlanList.getResult())) {
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 未查询到调整待回复的计划,customerCode:{},planTime:{}", crmIf003SDO.getCustomerCode(), crmIf003SDO.getPlanTime());
            return Lists.newArrayList();
        }
        if (salesPlanList.getResult().size() > 1) {
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 符合条件的调整计划存在多个,customerCode:{},planTime:{}", crmIf003SDO.getCustomerCode(), crmIf003SDO.getPlanTime());
            return Lists.newArrayList();
        }
        SalesPlan salesPlan = salesPlanList.getResult().get(0);
        // 2.2 查询出所有提报的货品
        BatchQueryByBizIdRequest bizIdRequest = BatchQueryByBizIdRequest.builder().build();
        bizIdRequest.setPlanId(String.valueOf(salesPlan.getParentId()));
        bizIdRequest.setBizIds(Lists.newArrayList(orgBusinessUnitCode));
        bizIdRequest.setPoolType("2");
        bizIdRequest.setBizType("5");
        bizIdRequest.setStart(0);
        bizIdRequest.setLimit(1000);
        Result<List<PlanScItem>> reportPlanScItems = getPlanScItemList(bizIdRequest);
        if (Objects.isNull(reportPlanScItems) || CollectionUtils.isEmpty(reportPlanScItems.getResult())) {
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 未查询到提报货品,customerCode:{},planTime:{}", crmIf003SDO.getCustomerCode(), crmIf003SDO.getPlanTime());
            return Lists.newArrayList();
        }
        orgUnitSalePlanMap.put(crmIf003SDO.getCustomerCode(), salesPlan);
        return reportPlanScItems.getResult();
    }

    private PlanScItem buildPlanScItem(Map<String, PlanScItem> planScItemMap,
                                       Map<String, SalesPlan> orgUnitSalePlanMap,
                                       Map<String, String> orgUnitCodeMap,
                                       Map<String, ScItemSDO> scItemMap,
                                       MnCrmIf003SDO mnCrmIf003SDO) {
        PlanScItem planScItem = new PlanScItem();
        String scItemCode = mnCrmIf003SDO.getScItemCode();
        if (StringUtils.isNotBlank(scItemCode)) {
            scItemCode = scItemCode.trim();
        }
        ScItemSDO itemSDO = scItemMap.get(scItemCode);
        SalesPlan salesPlan = orgUnitSalePlanMap.get(mnCrmIf003SDO.getCustomerCode());
        if (planScItemMap.containsKey(itemSDO.getScItemId())) {
            planScItem = planScItemMap.get(itemSDO.getScItemId());
        } else {
            String orgBusinessUnitCode = orgUnitCodeMap.get(mnCrmIf003SDO.getCustomerCode());
            if (Objects.isNull(salesPlan) || Objects.isNull(salesPlan.getId())) {
                return planScItem;
            }
            planScItem.setStatus(5);
            planScItem.setPlanId(Long.valueOf(salesPlan.getParentId()));
            planScItem.setPoolType(2);
            planScItem.setBizType(5);
            planScItem.setBizId(orgBusinessUnitCode);
            planScItem.setScItemId(itemSDO.getScItemId());
            planScItem.setScItemCategoryId(itemSDO.getLeafCategoryId());
            if (Objects.nonNull(itemSDO.getFeatures())) {
                Object object = itemSDO.getFeatures().get("scItemGroupCode");
                if (Objects.nonNull(object)) {
                    planScItem.setScItemGroup(object.toString());
                }
            }

            // 获取合同量、合同金额
            String year = DateUtils.toDateStr(Long.valueOf(salesPlan.getPlanTime()), "yyyy");
            String month = DateUtils.toDateStr(Long.valueOf(salesPlan.getPlanTime()), "MM");
            QueryQuantityListByAddressAndScItemRequest contractRequest = QueryQuantityListByAddressAndScItemRequest.builder().build();
            contractRequest.setContractYear(year);
            contractRequest.setPlanMonth(month);
            contractRequest.setOrgBusinessUnitCodes(Lists.newArrayList(orgBusinessUnitCode));
            contractRequest.setScItemIds(Lists.newArrayList(planScItem.getScItemId()));
            contractRequest.setType("2");
            contractRequest.setDataSource("2");
            QueryQuantityListByAddressAndScItemResponse contractResponse = planService.queryQuantityListByAddressAndScItem(contractRequest);
            if (Objects.nonNull(contractResponse) && CollectionUtils.isNotEmpty(contractResponse.getResult())) {
                MonthContractAndRollingCountResponse rollingCountResponse = contractResponse.getResult().stream().findFirst().get();
                planScItem.setMonthContractCount(rollingCountResponse.getMonthContractCount());
                planScItem.setMonthContractMoney(rollingCountResponse.getMonthContractMoney());
                planScItem.setBeforeMonthContractMoney(rollingCountResponse.getBeforeMonthContractMoney());
            }

            try {
                if (Objects.nonNull(planScItem.getScItemId())) {
                    // 获取价格: 2021 12.20产品逻辑，根据业务单元和货品取计划货品范围中的货品，取最大价格
                    SalesPlanScItemLoadListRequest loadListRequest = SalesPlanScItemLoadListRequest.newSalesPlanScItemLoadListRequestBuilder().orgBusinessUnitCode(orgBusinessUnitCode).scItemId(planScItem.getScItemId())
                            .status(1).build();
                    Result<List<SalesPlanScItem>> salesPlanScItemList = salesPlanScItemService.loadSalesPlanScItemList(loadListRequest);
                    if (Objects.nonNull(salesPlanScItemList) && CollectionUtils.isNotEmpty(salesPlanScItemList.getResult())) {
                        List<Long> collect = salesPlanScItemList.getResult().stream().map(SalesPlanScItem::getCostInsuranceFreight).filter(Objects::nonNull).collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(collect)) {
                            Long aLong = collect.stream().max(Long::compareTo).get();
                            planScItem.setCostInsuranceFreight(aLong);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail_get_price_error,scItemId={},{}", planScItem.getScItemId(),e.getMessage());
            }
        }
        // 2.2 模型转换
        Integer firstAdjustReturn = SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getEarlyAdjustReplyQuantity());
        Integer middleAdjustReturn = SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getMiddleAdjustReplyQuantity());
        Integer lateAdjustReturn = SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getLateAdjustReplyQuantity());
        // 计算三旬调整回复量 赋值
        if (firstAdjustReturn == null) {
            firstAdjustReturn = 0;
        }
        if (middleAdjustReturn == null) {
            middleAdjustReturn = 0;
        }
        if (lateAdjustReturn == null) {
            lateAdjustReturn = 0;
        }
        if (Objects.isNull(planScItem.getMonthFirstTaskCount())) {
            planScItem.setMonthFirstTaskCount(0);
        }
        if (Objects.isNull(planScItem.getMonthMiddleTaskCount())) {
            planScItem.setMonthMiddleTaskCount(0);
        }
        if (Objects.isNull(planScItem.getMonthLastTaskCount())) {
            planScItem.setMonthLastTaskCount(0);
        }
        // pd确认：调整回复量=crm调整回复量-任务量
        planScItem.setMonthFirstAdjustReturnCount(firstAdjustReturn - planScItem.getMonthFirstTaskCount());
        planScItem.setMonthMiddleAdjustReturnCount(middleAdjustReturn - planScItem.getMonthMiddleTaskCount());
        planScItem.setMonthLastAdjustReturnCount(lateAdjustReturn - planScItem.getMonthLastTaskCount());

        // 003回复的时候计划汇总的任务量为0，赋值给extend要计算到岸金额
        Integer taskCount = Objects.isNull(planScItem.getTaskCount()) ? 0 : planScItem.getTaskCount();
        planScItem.setTaskOutboundMoney(taskCount*planScItem.getOutboundPrice());
        planScItem.setAdjustOutboundMoney(planScItem.getAdjustCount()*planScItem.getOutboundPrice());

        // 计算调整中的满足度
        // 折前满足度=（任务量+调整回复量）*货品常规价
        Integer monthFirstAdjustReturnCount = Objects.isNull(planScItem.getMonthFirstAdjustReturnCount()) ? 0 : planScItem.getMonthFirstAdjustReturnCount();
        Integer monthMiddleAdjustReturnCount = Objects.isNull(planScItem.getMonthMiddleAdjustReturnCount()) ? 0 : planScItem.getMonthMiddleAdjustReturnCount();
        Integer monthLastAdjustReturnCount = Objects.isNull(planScItem.getMonthLastAdjustReturnCount()) ? 0 : planScItem.getMonthLastAdjustReturnCount();
        Integer AdjustReturnCount = monthFirstAdjustReturnCount + monthMiddleAdjustReturnCount + monthLastAdjustReturnCount;
        Integer taskAdjustCount = taskCount + AdjustReturnCount;
        Long costInsuranceFreight = Objects.isNull(planScItem.getCostInsuranceFreight()) ? 0 : planScItem.getCostInsuranceFreight();
        long notBeforeContractSatisfactionMoney = taskAdjustCount * costInsuranceFreight;
        // 折前任务金额
        long beforeContractSatisfactionMoney = taskCount * costInsuranceFreight;
        planScItem.setBeforeTaskMoney(beforeContractSatisfactionMoney);
        long beforeContractMoney = Objects.isNull(planScItem.getBeforeMonthContractMoney()) ? 0 : planScItem.getBeforeMonthContractMoney();
        BigDecimal beforeContractSatisfaction = CalculatePercentage.retainTwoBigDecimal(new BigDecimal(notBeforeContractSatisfactionMoney), new BigDecimal(beforeContractMoney));
        planScItem.setBeforeContractSatisfaction(beforeContractSatisfaction);
        // 折后满足度=（任务量+调整回复量）*货品常规价*（1-预估价格折扣率）
        if (StringUtils.isNotBlank(salesPlan.getFeatures())) {
            JSONObject jsonObject = JSONObject.parseObject(salesPlan.getFeatures());
            if (jsonObject.getString("estimateDiscount") != null) {
                BigDecimal estimateDiscount = new BigDecimal(jsonObject.get("estimateDiscount").toString());
                if (planScItem.getBeforeTaskMoney() != null) {
                    planScItem.setTaskMoney(calculateTaskMoney(estimateDiscount, planScItem.getBeforeTaskMoney()));
                }
                // 折后满足度
                Long taskMoney = Objects.isNull(planScItem.getTaskMoney()) ? 0 : planScItem.getTaskMoney();
                Long monthContractMoney = Objects.isNull(planScItem.getMonthContractMoney()) ? 0 : planScItem.getMonthContractMoney();
                BigDecimal contractSatisfaction = CalculatePercentage.retainTwoBigDecimal(new BigDecimal(taskMoney), new BigDecimal(monthContractMoney));
                planScItem.setContractSatisfaction(contractSatisfaction);
            }
        }
        return planScItem;
    }

    private boolean saveOrUpdateScItemExtend(List<PlanScItemExtend> extendList, Map<String, PlanScItemExtend> planScItemExtendMap) {
        for (PlanScItemExtend planScItemExtend : extendList) {
            PlanScItemExtend scItemExtend = planScItemExtendMap.get(planScItemExtend.getScItemId());
            if (null == scItemExtend) {
                PlanScItemExtend extend = new PlanScItemExtend();
                BeanUtils.copyProperties(planScItemExtend, extend);
                extend.setGmtCreate(new Date());
                extend.setGmtModified(new Date());
                CreatePlanScItemExtendResponse extendResponse = planScItemExtendService.createPlanScItemExtend(extend);
                log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_create_planScItemExtend_result:{}", JSONObject.toJSONString(extendResponse));
            } else {
                PlanScItemExtend updateRequest = new PlanScItemExtend();
                BeanUtils.copyProperties(planScItemExtend, updateRequest);
                updateRequest.setId(scItemExtend.getId());
                updateRequest.setGmtModified(new Date());
                UpdatePlanScItemExtendResponse updatePlanScItemExtendResponse = planScItemExtendService.updatePlanScItemExtend(updateRequest);
                log.info("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_update_planScItemExtend_result:{}", JSONObject.toJSONString(updatePlanScItemExtendResponse));
            }
        }
        return true;
    }

    private Result<List<PlanScItem>> getPlanScItemList(BatchQueryByBizIdRequest bizIdRequest) {
        Result<List<PlanScItem>> listResult = new Result<>();
        try {
            listResult = planScItemService.batchQueryByBizId(bizIdRequest);
        } catch (Exception e) {
            log.error("未查询到调整中的月度计划数据");
            throw new FacadeException("月度计划货品查询失败");
        }
        return listResult;
    }

    private Result<List<SalesPlan>> getSalesPlanList(LoadSalesPlanListRequest planListRequest) {
        Result<List<SalesPlan>> listResult = new Result<>();
        try {
            listResult = salesPlanService.loadSalesPlanList(planListRequest);
        } catch (Exception e) {
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 未找到调整中的月度计划");
        }
        return listResult;
    }

    public Long calculateTaskMoney(BigDecimal estimateDiscount, Long beforeMoney) {
        BigDecimal multiply = estimateDiscount.multiply(new BigDecimal("0.01").setScale(2, BigDecimal.ROUND_HALF_UP));
        BigDecimal subtract = new BigDecimal(1).subtract(multiply);
        return new BigDecimal(beforeMoney).multiply(subtract).longValue();
    }

    private Result<List<ScItemSDO>> getScItemByOuterId(String outerId) {
        String itemCode = SapAndCrmFieldDealUtils.generateIdField(outerId);
        if (StringUtils.isNotBlank(itemCode)) {
            itemCode = itemCode.trim();
            if (itemCode.length() >= 12) {
                itemCode = org.apache.commons.lang.StringUtils.substring(itemCode, itemCode.length() - 12);
            }
        }
        List<String> code = Lists.newArrayList(itemCode);
        Map map = new HashMap();
        map.put("outerIdList", code);
        SearchScItemRequest build = SearchScItemRequest.builder().build();
        build.setSearchReqDTO(map);
        Result<List<ScItemSDO>> result = baseDataService.searchScItem(build);
        return result;
    }

    private String getOrgBusinessUnitCode(MnCrmIf003SDO mnCrmIf003SDO) {
        String orgBusinessUnitCode = "";
        try {
            // 根据公司outCode查询出bizId
            BatchQueryCompanyRequest companyRequest = BatchQueryCompanyRequest.builder()
                    .outCode(Lists.newArrayList(mnCrmIf003SDO.getCustomerCode()))
                    .build();
            Map map = (Map) bcOtsService.batchQueryCompany(companyRequest);
            Map result = (Map) map.get("result");
            List<Map> content = (List<Map>) result.get("content");
            if (CollectionUtils.isNotEmpty(content)) {
                Map company = content.get(0);
                String bizId = (String) company.get("id");
                // 根据bizId，bizType查询对应的组织id
                BaselineGetOrganizationByTypeRequest byTypeRequest = BaselineGetOrganizationByTypeRequest.builder().type("103").bizId(bizId).bizType("COMPANY").build();
                Map organizationByType = (Map) baseDataService.baselineGetOrganizationByType(byTypeRequest);
                List<Map> orgResultMap = (List<Map>) organizationByType.get("result");
                if (CollectionUtils.isNotEmpty(orgResultMap)) {
                    orgBusinessUnitCode = (String) ((Map) (orgResultMap.get(0).get("organizationSDO"))).get("id");
                }
            }
        } catch (Exception e) {
            log.error("MnCrmIf003ServiceImpl#externalReplySalePlanAdjust_fail 组织转换异常", e);
        }
        return orgBusinessUnitCode;
    }

    private long getPlanTime(MnCrmIf003SDO mnCrmIf003SDO) {
        SimpleDateFormat yyyyMM = new SimpleDateFormat("yyyyMM");
        long time = 0;
        try {
            time = yyyyMM.parse(mnCrmIf003SDO.getPlanTime()).getTime();
        } catch (ParseException e) {
            log.error("日期转换失败");
        }
        return time;
    }

    private List<String> getScItemCodesBy003SDOs(List<MnCrmIf003SDO> if003SDOs) {
        Set<String> set = if003SDOs.stream().map(MnCrmIf003SDO::getScItemCode).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        return Lists.newArrayList(set);
    }

    private Map<String, ScItemSDO> getScItemByOuterIds(List<String> outerIds) {
        Map<String, ScItemSDO> scItemSDOMap = Maps.newHashMap();
        SearchScItemRequest build = SearchScItemRequest.builder().build();
        List<String> stringList = outerIds.stream().map(it -> {
            String itemCode = it;
            if (StringUtils.isNotBlank(itemCode)) {
                itemCode = itemCode.trim();
                if (itemCode.length() >= 12) {
                    return StringUtils.substring(itemCode, itemCode.length() - 12);
                }
            }
            return itemCode;
        }).collect(Collectors.toList());

        List<String> outerId = Lists.newArrayList(stringList);
        Map map = new HashMap();
        map.put("outerIdList", outerId);
        build.setSearchReqDTO(map);
        build.setPageSize(stringList.size());
        Result<List<ScItemSDO>> result = baseDataService.searchScItem(build);
        if (Objects.isNull(result) || CollectionUtils.isEmpty(result.getResult())) {
            log.error("未查询到启用的货品，货品不存在或不可用，scItemCodes：{}", outerIds.toString());
            return scItemSDOMap;
        }
        return result.getResult().stream().collect(Collectors.toMap(ScItemSDO::getOuterId, o -> o));
    }


    private MonthlyPlanOfCcommerce convertMonthlyPlanOfCommerce(MnCrmIf003SDO mnCrmIf003SDO, OrganizationSDO orgBusiness, Result<List<MonthlyPlanOfCcommerce>> listResult) {
        MonthlyPlanOfCcommerce monthlyPlanOfCcommerce = new MonthlyPlanOfCcommerce();
        monthlyPlanOfCcommerce.setOrgBusinessCode(orgBusiness.getId());
        monthlyPlanOfCcommerce.setPlanTime(mnCrmIf003SDO.getPlanTime());
        monthlyPlanOfCcommerce.setOrgSaleOrganizationCode(mnCrmIf003SDO.getSalesOrganizationCode());
        monthlyPlanOfCcommerce.setCustomerCode(mnCrmIf003SDO.getCustomerCode());
        monthlyPlanOfCcommerce.setOuterId(mnCrmIf003SDO.getScItemCode());
        monthlyPlanOfCcommerce.setScItemGroupCode(mnCrmIf003SDO.getScItemGroup());
        if (listResult.getResult().size() == 1) {
            listResult.getResult().forEach(it -> {
                monthlyPlanOfCcommerce.setMonthFirstPlannedQuantity(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthFirstPlannedQuantity())));
                monthlyPlanOfCcommerce.setMonthFirstReturnCount(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthFirstReturnCount())));
                monthlyPlanOfCcommerce.setMonthMiddlePlannedQuantity(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthMiddlePlannedQuantity())));
                monthlyPlanOfCcommerce.setMonthMiddleReturnCount(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthMiddleReturnCount())));
                monthlyPlanOfCcommerce.setMonthLastPlannedQuantity(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthLastPlannedQuantity())));
                monthlyPlanOfCcommerce.setMonthLastReturnCount(SapAndCrmFieldDealUtils.toInteger(String.valueOf(it.getMonthLastReturnCount())));
            });
        } else {
            monthlyPlanOfCcommerce.setMonthFirstPlannedQuantity(0);
            monthlyPlanOfCcommerce.setMonthFirstReturnCount(0);
            monthlyPlanOfCcommerce.setMonthMiddlePlannedQuantity(0);
            monthlyPlanOfCcommerce.setMonthMiddleReturnCount(0);
            monthlyPlanOfCcommerce.setMonthLastPlannedQuantity(0);
            monthlyPlanOfCcommerce.setMonthLastReturnCount(0);
        }

        monthlyPlanOfCcommerce.setMonthPlannedQuantity(monthlyPlanOfCcommerce.getMonthFirstPlannedQuantity() +
                monthlyPlanOfCcommerce.getMonthMiddlePlannedQuantity() + monthlyPlanOfCcommerce.getMonthLastPlannedQuantity());
        monthlyPlanOfCcommerce.setMonthReturnCount(monthlyPlanOfCcommerce.getMonthFirstReturnCount() +
                monthlyPlanOfCcommerce.getMonthMiddleReturnCount() + monthlyPlanOfCcommerce.getMonthLastReturnCount());
        //上旬修订确认量
        monthlyPlanOfCcommerce.setMonthFirstReviseConfirmCount(SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getEarlyAdjustReplyQuantity()));
        //中旬修订确认量
        monthlyPlanOfCcommerce.setMonthMiddleReviseConfirmCount(SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getMiddleAdjustReplyQuantity()));
        //下旬修订确认量
        monthlyPlanOfCcommerce.setMonthLastReviseConfirmCount(SapAndCrmFieldDealUtils.toInteger(mnCrmIf003SDO.getLateAdjustReplyQuantity()));
        //本月修订确定量
        monthlyPlanOfCcommerce.setMonthReviseConfirmCount(monthlyPlanOfCcommerce.getMonthFirstReviseConfirmCount() + monthlyPlanOfCcommerce.getMonthMiddleReviseConfirmCount() +
                monthlyPlanOfCcommerce.getMonthLastReviseConfirmCount());

        monthlyPlanOfCcommerce.setGmtModified(new Date());
        return monthlyPlanOfCcommerce;
    }
}
